/*! \file variables.c
 *  \brief Functions to manipulate list of variables. 
 *  \author Lluis Garrido
 *
 *  This file contains the structures necessary for
 *  manipulating the structure list_variables.
 */

#include "variables.h"


/*! 
 *  \brief Allocate a list_variables structure. 
 *
 *  \param[in] nitems  The maximum number of variables the list may hold. 
 *
 *  \return A pointer to the allocated structure. 
 *
 */

struct list_variables *list_variables_allocate(int nitems)
{
  int i;
  struct list_variables *l;

  assert(nitems > 0);

  l = (struct list_variables *) malloc(sizeof(struct list_variables));

  if (!l)
  {
    printf("ERROR: not enough memory.\n");
    exit(EXIT_FAILURE);
  }

  l->el = (struct variable *) malloc(sizeof(struct variable) * nitems);

  if (!l->el)
  {
    printf("ERROR: not enough memory.\n");
    exit(EXIT_FAILURE);
  }

  l->nitems = nitems;
  l->currid    = 1;

  for(i = 0; i < nitems; i++)
    l->el[i].variable_id = VARIABLE_ID_NONE;

  return l;
}

/*! 
 *  \brief Get the numerical value associated to a variable. 
 *
 *  \param[in] lva          A pointer to the list of variables. 
 *  \param[in] variable_id  The identifier of the variable (see ::list_variables_set_variable, ::list_variables_get_variable_id)
 *
 *  \return The numerical value associated to the variable. 
 *
 */

double list_variables_get_value(struct list_variables *lva, unsigned int variable_id)
{
  BOOL found = FALSE;

  int i;

  for(i = 0; i < lva->nitems; i++)
  {
    if (lva->el[i].variable_id == variable_id)
    {
      found = TRUE;
      break;
    }
  }

  if (!found)
  {
    printf("ERROR: variable is not defined.\n");
    exit(EXIT_FAILURE);
  }

  return lva->el[i].value;
}

/*! 
 *  \brief Get the identifier of the variable. 
 *
 *  \param[in] lva   A pointer to the list of variables. 
 *  \param[in] name  The name of the variable. 
 *
 *  \return The identifier associated to the variable. 
 *
 */

unsigned int list_variables_get_variable_id(struct list_variables *lva, char *name)
{
  BOOL found = FALSE;
  int i, ret = VARIABLE_ID_NONE;

  for(i = 0; i < lva->nitems; i++)
  {
    if ((lva->el[i].variable_id != VARIABLE_ID_NONE) && (strncmp(name, lva->el[i].name, MAX_SIZE_VARIABLE) == 0))
    {
      found = TRUE;
      break;
    }
  }

  if (found)
    ret = lva->el[i].variable_id;
  
  return ret;
}

/*! 
 *  \brief Get the name of a variable. 
 *
 *  \param[in] lva          A pointer to the list of variables. 
 *  \param[in] variable_id  The identifier of the variable. 
 *
 *  \return The name associated to the variable. 
 *
 */

char *list_variables_get_name(struct list_variables *lva, int variable_id)
{
  BOOL found = FALSE;

  int i;

  for(i = 0; i < lva->nitems; i++)
  {
    if (lva->el[i].variable_id == variable_id)
    {
      found = TRUE;
      break;
    }
  }

  if (!found)
  {
    printf("ERROR: variable is not defined.\n");
    exit(EXIT_FAILURE);
  }

  return lva->el[i].name;
}

/*! 
 *  \brief Set the value of a variable.
 *
 *  Assign a value to a variable. If the variable does not 
 *  exist, it is created and inserted into the list of variables. 
 *
 *  \param[in] lva     A pointer to the list of variables. 
 *  \param[in] name    The name of the variable.
 *  \param[in] value   The value associated to the variable.
 *
 *  \return The identifier associated to the variable. 
 *
 */

int list_variables_set_variable(struct list_variables *lva, char *name, double value)
{
  BOOL found = FALSE;
  int i, ret;

  // First check if the variable already exists
  i = list_variables_get_variable_id(lva, name);

  // If the returned value is VARIABLE_ID_NONE the variable does 
  // not exist, otherwise 'ret' contains the id of the variable.
  if (i == VARIABLE_ID_NONE)
  {
    // Search for a free entry in the list

    for(i = 0; i < lva->nitems; i++)
    {
      if (lva->el[i].variable_id == VARIABLE_ID_NONE)
      {
	// Free entry found

	found = TRUE;
	break;
      }
    }

    if (!found)
    {
      printf("ERROR: no more space to allocate variables");
      exit(EXIT_FAILURE);
    }
  }

  lva->el[i].variable_id = lva->currid;
  strncpy(lva->el[i].name, name, MAX_SIZE_VARIABLE);
  lva->el[i].value = value;

  ret = lva->currid;
  lva->currid++;

  return ret;
}

/*! 
 *  \brief Insert default variables into the list. 
 *
 *  Inserts default variables (PI and E) into the 
 *  list of variables.
 *
 *  \param[in] lva     A pointer to the list of variables. 
 *
 */

void list_variables_init_default(struct list_variables *lva)
{
  list_variables_set_variable(lva, "pi", M_PI);
  list_variables_set_variable(lva, "e", M_E);
}

/*! 
 *  \brief Free a list_variables structure. 
 *
 *  \param[in] lva  The list of variables to be freed.
 *
 */

void list_variables_free(struct list_variables *lva)
{
  assert(lva != NULL);
  assert(lva->el != NULL);

  free(lva->el);
  free(lva);
}


